home *** CD-ROM | disk | FTP | other *** search
- * INDEX.SNO
- *
- * Formats a mail digest file for printing. Does pagination, produces a
- * Table of Contents and an Index. The Index is based on entries in the
- * message headers of the form
- *
- * Keywords: xxxx, xxxx, xxxx, "xxx, xxxx", xxxx
- * Cross-Ref: string
- *
- * A list of zero or more keywords may be included, separated by commas.
- * If the keyword itself is to contain a comma, it is enclosed in doublequotes.
- * The cross ref string is entered literally in the index. Examples:
- *
- * Keywords: Blort
- * Keywords: Foo, Bar, This and That, "Law, Murphy's", Baz
- * Cross-Ref: Murphy's Law, see Law, Murphy's
- *
- * Any particular Cross-Reference need be entered in the file only once.
- * The index is sorted in ASCII order, so alphabetic case matters.
- *
- * The table of contents depends on the subject of each digest containing
- * the words "Info-Kermit Digest Vx #y", where x & y are the vol/issue number.
- * The end of a digest is detected by "End of InfoxxxxxDigest" where a
- * digest message header would start.
- *
- * F. da Cruz, C. Gianone, CUCCA, May 1986
- *
- * Modified May 88 to work with VAX spitbol
- * Modified Nov 88 to work with UNIX MM mail format
- * Modified Oct 91 to allow XREF as synonym for CROSS-REF
-
- &TRIM = 1
- PAGEWID = 79
- PAGELEN = 58
-
- * Patterns
-
- NULL =
- &ALPHABET POS(13) (LEN(1) . CR)
- &ALPHABET POS(10) (LEN(1) . LF)
- CRLF = CR LF
- &ALPHABET POS(34) (LEN(1) . DQ)
- BLANK = ' '
- &ALPHABET POS(9) (LEN(1) . HT)
- WS = BLANK HT
- &ALPHABET POS(12) (LEN(1) . FF)
- LOWER = 'abcdefghijklmnopqrstuvwxyz'
- UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
- DIGITS = '0123456789'
-
- KEYS = 'Keywords' | 'Keyword' | 'KEYWORDS' | 'KEYWORD'
- + | 'keywords' | 'keyword'
- REFS = 'Cross-Ref' | 'Cross-Reference' | 'CROSS-REF'
- + | 'XREF' | 'Xref' | 'xref'
- KEYW = POS(0) KEYS ':' BREAK(WS) REM . KEY
- XREF = POS(0) REFS ':' BREAK(WS) REM . SEE
-
- SUBJ = POS(0) 'SUBJECT:' BREAK(WS) REM . TITLE
- ISUB = 'INFO' LEN(1) 'KERMIT' LEN(1) 'DIGEST V'
- + SPAN(DIGITS) . VOLUME SPAN(BLANK) '#' SPAN(DIGITS) . ISSUE
- ASUB = POS(0) 'subject:' | 'SUBJECT:' | 'Subject:' SPAN(WS) REM . SUB
-
- * Table, array declarations
-
- IXTB = TABLE()
- CONTENTS = ARRAY(500)
- INDEX = ARRAY('1000,2')
- II = 0
- CC = 0
-
- * Newpage function definition. Starts a new page, puts heading on top
- * composed of current digest title and page number. Set PAGE = -1 to
- * disable page number. Reverses page headings.
-
- DEFINE('NEWPAGE()') :(NEWPAGX)
- NEWPAGE OUTPUT = FF
- GE(PAGE,0) :S(NEWP2)
- OUTPUT = TITLE
- OUTPUT = :(NEWP4)
- NEWP2 PAGE = PAGE + 1
- X = 'Page ' PAGE
- EQ(REMDR(PAGE,2),1) :S(NEWP3)
- OUTPUT = X LPAD(TITLE,PAGEWID - SIZE(X)) :(NEWP4)
- NEWP3 OUTPUT = TITLE LPAD(X,PAGEWID - SIZE(TITLE))
- NEWP4 OUTPUT =
- LC = 3 :(RETURN)
- NEWPAGX
-
- * Function to output a line. If the line is longer than the page
- * width, it is broken at the nearest blank, and two (or more) lines are
- * output. If the bottom of the page is reached, a new page is started.
-
- DEFINE('OUTLIN(S)') :(OUTLINX)
- OUTLIN :(OUTLIN2)
- OUTLOOP IDENT(S,NULL) :S(RETURN)
- OUTLIN2 P = PAGEWID
- P = GE(P,SIZE(S)) SIZE(S) :S(OUTGB2)
-
- OUTFB S POS(P) BLANK :S(OUTGB)
- P = GT(P,0) P - 1 :S(OUTFB)
-
- OUTGB P = EQ(P,0) PAGEWID
- P = GE(P,SIZE(S)) SIZE(S)
-
- OUTGB2 S LEN(P) . S1 = NULL
- OUTPUT = S1
- LC = LT(LC,PAGELEN) LC + 1 :S(OUTLOOP)
- NEWPAGE() :(OUTLOOP)
- OUTMORE
- :(OUTLIN)
- OUTLINX
-
- * Program start
-
- START PAGE = 0
- LC = 0
-
- * Here to initialize a new digest issue
-
- INITISS TITLE = NULL
- VOLUME = 0
- ISSUE = 0
-
- * New issue, discard mail header.
-
- BIGHDR LINE = INPUT :F(DONE)
- IDENT(LINE,NULL) :S(BODY)
- TEMP = REPLACE(LINE,LOWER,UPPER)
- TEMP SUBJ
- TITLE POS(0) SPAN(WS) = NULL :(BIGHDR)
-
- * Body of message, starts with "table of contents" (list of subjects)
-
- BODY TITLE ISUB :F(INITISS)
- NEWPAGE()
- TERMINAL = '** V' VOLUME ' #' ISSUE
- X = 'Volume ' VOLUME ', Number ' ISSUE
- CC = CC + 1
- CONTENTS<CC> = X LPAD(PAGE,PAGEWID - SIZE(X))
-
- TOC LINE = INPUT :F(DONE)
- OUTLIN(LINE)
- TOC2 LINE POS(0) '---' :F(TOC)
-
- * Here for digest messages.
-
- MSG0 LINE = INPUT :F(DONE)
- TEMP = REPLACE(LINE,LOWER,UPPER)
- OUTLIN(LINE)
- IDENT(LINE,NULL) :S(MSG0)
-
- * Look for message header with keywords, or else end of digest.
-
- MSGS TEMP POS(0) 'END' LEN(1) 'OF' LEN(1) 'INFO' ARB 'DIGEST'
- + :F(MSGHDX)
-
- * Here for end of digest. Gobble up junk until next digest.
-
- EOD LINE = INPUT :F(DONE)
- LINE POS(0) 'From ' :F(EOD)S(INITISS)
-
- * New message in current digest. Read headers, looking for keywords.
-
- MSGHDX LINE = INPUT :F(DONE)
- OUTLIN(LINE)
- IDENT(LINE,NULL) :S(MSGBODY)
- TEMP = REPLACE(LINE,LOWER,UPPER)
- LINE ASUB :F(MSGHDY)
- TEMP POS(0) 'RE:' :S(MSGHDY)
- TEMP 'NEW ' | 'ANNOUNC' | 'AVAILAB' | 'RELEAS' | 'PROPOS' | 'UPDATE'
- + :F(MSGHDY)
- CC = CC + 1
- CONTENTS<CC> = ' ' SUB LPAD(PAGE,PAGEWID - SIZE(SUB) - 2)
- :(MSGS)
- MSGHDY LINE KEYW :S(KEYWORD)
- LINE XREF :F(MSGS)
-
- * Got a cross reference to enter.
-
- SEE POS(0) SPAN(WS) = NULL
- KW = SEE
- SW = SEE
- REPLACE(SW,LOWER,UPPER)
-
- REFADD T = IXTB<SW>
- X = BLANK
- DIFFER(T,NULL) :S(KEYSCAN)
- II = LE(II,1000) II + 1 :S(KEYADD2)
- TERMINAL = "** Index overflow - Fatal!" :(END)
-
- * Got keyword header, enter into index.
-
- KEYWORD KEY = KEY ','
-
- * Get next keyword from list.
-
- KEYSCAN KEY POS(0) SPAN(WS) = NULL
- IDENT(KEY,NULL) :S(MSGS)
- KEY POS(0) (DQ (BREAK(DQ) . KW) DQ ',') = NULL :S(KEYINDX)
- KEY (BREAK(',') . KW ',') = NULL :F(MSGS)
-
- * Make an all uppercase sort key from the keyword, and a trial page ref.
-
- KEYINDX KW = TRIM(KW)
- SW = REPLACE(KW,LOWER,UPPER)
- X = ', ' PAGE
-
- * See if this is a new item. If so, create a new array entry.
-
- KEYADD T = IXTB<SW>
- DIFFER(T,NULL) :S(KEYADD4)
- II = LE(II,1000) II + 1 :S(KEYADD2)
- TERMINAL = "** Index overflow - Fatal!" :(END)
-
- * Adding a new one
-
- KEYADD2 IXTB<SW> = II
- INDEX<II,1> = KW
- INDEX<II,2> = X :(KEYSCAN)
-
- * See if the page reference should be added, and in which form.
-
- KEYADD4
- INDEX<T,2> (BLANK | '-') PAGE RPOS(0) :S(KEYSCAN)
- INDEX<T,2> LEN(1) . PUNC SPAN(DIGITS) . LAST RPOS(0) :F(KEYADD5)
- EQ(PAGE,LAST + 1) :F(KEYADD5)
- X = DIFFER(PUNC,'-') '-' PAGE :S(KEYADD5)
- INDEX<T,2> LAST RPOS(0) = PAGE :(KEYSCAN)
- KEYADD5 INDEX<T,2> = INDEX<T,2> X :(KEYSCAN)
-
- * Now read and output the message body.
-
- MSGBODY LINE = INPUT :F(DONE)
- OUTLIN(LINE)
- LINE POS(0) '---' :S(MSG0)
- :(MSGBODY)
- * End of input file. Now output the index.
-
- DONE
- *** TERMINAL = '** Input complete, sorting Index...'
- A = SORT(IXTB) :S(IDXOUT)
- TERMINAL = '** Error converting index table' :(TOCOUT)
-
- IDXOUT EQ(REMDR(PAGE,2),1) NEWPAGE()
- TITLE = 'Index'
- NEWPAGE()
- I = 1
-
- IDXLOOP J = A<I,2>
- K = INDEX<J,1> INDEX<J,2>
- OUTLIN(K)
- I = LT(I,II) I + 1 :S(IDXLOOP)
-
- * And put the table of contents on the end.
-
- TOCOUT EQ(REMDR(PAGE,2),1) NEWPAGE()
- PAGE = -1
- TITLE = 'Table of Contents'
- NEWPAGE()
- I = 0
- TOCLOOP OUTLIN(CONTENTS<I>)
- I = LE(I,CC) I + 1 :S(TOCLOOP)
-
- END
-